using System;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using Ah.Testudin.Engine;
using Ah.Testudin.Engine.Content;
using Ah.Testudin.Engine.Events;
using Ah.Testudin.Engine.Graphics;
using Ah.Testudin.Engine.Physics;
using Ah.Testudin.Game.Infrastructure;
using Ah.Testudin.Engine.Processes;
using Ah.Testudin.Engine.Actors.Spawning;
using Ah.Testudin.Engine.Graphics.Scenes;

namespace Ah.Testudin.Game
{
    public class TestudinGame : Microsoft.Xna.Framework.Game
    {
        #region Private Member Variables

        private readonly GraphicsDeviceManager _graphicsDeviceManager;

        private IGameStateMachine _gameStateMachine;

        #endregion

        #region Constructors

        public TestudinGame()
        {
            _graphicsDeviceManager = new GraphicsDeviceManager(this);
        }

        #endregion

        #region Overrides

        protected override void LoadContent()
        {
            SpriteBatch spriteBatch = new SpriteBatch(_graphicsDeviceManager.GraphicsDevice);

            GraphicsDeviceRendererSingleton.Initialize(
                _graphicsDeviceManager.GraphicsDevice,
                spriteBatch);

            IServiceProvider serviceProvider = new TestudinServiceProvider(_graphicsDeviceManager);

            IEventManager eventManager = EventManagerSingleton.Instance;

            ITestudinContentManager contentManager = new TestudinContentManager(serviceProvider);

            TestudinContentManagerSingleton.Initialize(contentManager);

            IPhysicsSimulator physicsSimulator = new BulletSharpPhysicsSimulator(
                new BulletDebugDrawer(
                    new BasicEffect(_graphicsDeviceManager.GraphicsDevice),
                    GraphicsDeviceRendererSingleton.Instance,
                    GetWorldView,
                    GetWorldProjection)
                    {
                        DebugMode = BulletSharp.DebugDrawModes.None
                    });

            IProcessManager processManager = new ProcessManager();

            IActorSpawner actorSpawner = new ActorSpawner(
                new ActorBuilderFactory(
                    new CubeActorBuilder(
                        contentManager,
                        eventManager,
                        physicsSimulator),

                    new MissileActorBuilder(
                        contentManager,
                        eventManager,
                        physicsSimulator),
                        
                    new ExplosionActorBuilder(
                        contentManager,
                        eventManager)));

            _gameStateMachine = new GameStateMachine(
                _graphicsDeviceManager.GraphicsDevice.Viewport.Width,
                _graphicsDeviceManager.GraphicsDevice.Viewport.Height,
                eventManager,
                physicsSimulator,
                processManager,
                actorSpawner);

            _gameStateMachine.LoadGame();
        }

        protected override void Update(GameTime gameTime)
        {
            _gameStateMachine.HandleInput();

            _gameStateMachine.Update(gameTime);

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            _gameStateMachine.Render();

            _gameStateMachine.RenderDiagnostics(gameTime);

            base.Draw(gameTime);
        }

        #endregion

        #region Private Methods

        private Matrix GetWorldView()
        {
            // TODO: Need to grab world view from the InGameState and pass it back

            throw new NotImplementedException();
        }

        private Matrix GetWorldProjection()
        {
            // TODO: Need to grab world projection from the InGameState and pass it back

            throw new NotImplementedException();
        }

        #endregion
    }
}